package com.momoauth.common.log.aspect;

import com.alibaba.fastjson2.JSON;
import com.momoauth.common.log.annotation.SystemLog;
import com.momoauth.common.log.dao.SystemLogDao;
import com.momoauth.common.log.entity.System_Log;
import com.momoauth.common.log.utils.HttpUtil;
import com.momoauth.common.log.utils.SnowFlakeIdUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.*;

@Slf4j
@Aspect
public class SystemLogAspect {

    @Resource
    SystemLogDao systemLogDao;

    private static long startTime;
    System_Log sysLog = new System_Log();
    boolean insertSql = false;

    @Pointcut("@annotation(com.momoauth.common.log.annotation.SystemLog)")
    public void pointcut() {}

    @Before("pointcut()")
    public void before(JoinPoint joinPoint) {
        startTime = System.currentTimeMillis(); //执行开始时间
        HttpServletRequest request = HttpUtil.currentRequest();
        StringBuilder sb = new StringBuilder();
        getJoinPointData(joinPoint, sb);
        getRequestData(request, sb);
        log.info(sb.toString());
    }

    @After("pointcut()")
    public void after() {
        long executeTime = System.currentTimeMillis() - startTime;
        // 根据insertSql参数的值决定是否插入SQL
        if (insertSql) {
            sysLog.setExecuteTime(String.valueOf(executeTime));
        }
        log.info("【请求耗时】：" + executeTime + "毫秒"); //执行结束时间
    }

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        Object result = point.proceed();
        String returnValue = JSON.toJSONString(result);
        // 根据insertSql参数的值决定是否插入SQL
        if (insertSql) {
            sysLog.setReturnValue(returnValue);
            SnowFlakeIdUtil idWorker = new SnowFlakeIdUtil(3, 1);
            sysLog.setLogId(idWorker.nextId());
            systemLogDao.insertSystemLog(sysLog);
        }
        log.info("【返回值】：" + returnValue);
        return result;
    }

    /**
     * 从JoinPoint对象获取数据
     * @param joinPoint
     * @param sb
     */
    private void getJoinPointData(JoinPoint joinPoint, StringBuilder sb) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = method.getName();
        SystemLog systemLog = method.getAnnotation(SystemLog.class);
        String value = systemLog.value();
        String description = systemLog.description();
        // 根据insertSql参数的值决定是否插入SQL
        if (systemLog.insertSql()) {
            insertSql = true;
            sysLog.setClassName(className);
            sysLog.setMethodName(methodName);
            sysLog.setValue(value);
            sysLog.setDescription(description);
        }
        sb.append("\n【类名】：").append(className);
        sb.append("\n【方法名】：").append(methodName);
        sb.append("\n【@SystemLog的value值】：").append(value);
        sb.append("\n【@SystemLog的description值】：").append(description);
    }

    /**
     * 从HttpServletRequest对象获取数据
     * @param request
     * @param sb
     */
    private void getRequestData(HttpServletRequest request, StringBuilder sb) {
        String requestMethod = request.getMethod();
        String requestURL = request.getRequestURL().toString();
        String requestIp = HttpUtil.getIpAddress(request);
        Map<String, String[]> parameterMap = request.getParameterMap();
        String parameters = JSON.toJSONString(parameterMap);
        // 根据insertSql参数的值决定是否插入SQL
        if (insertSql) {
            sysLog.setRequestMethod(requestMethod);
            sysLog.setRequestUrl(requestURL);
            sysLog.setRequestIp(requestIp);
            sysLog.setParameters(parameters);
        }
        sb.append("\n【请求方式】：").append(requestMethod);
        sb.append("\n【请求URL】：").append(requestURL);
        sb.append("\n【请求IP】：").append(requestIp);
        sb.append("\n【请求参数】：").append(parameters);
    }
}
